using System;
using System.Windows.Forms;
using System.Drawing;
using System.Data;
using System.Collections;

namespace ADN.Windows.Ctrl
{

	public class JoinTextBoxColumn : DataGridTextBoxColumn
	{

		// Store information necessary to retrieve fields.

		private string relationName;
		private DataColumn parentField;

		public JoinTextBoxColumn(string RelationName, DataColumn ParentField)
		{
			relationName	= RelationName;
			parentField		= ParentField;
			base.ReadOnly	= true;
		}

		protected override object GetColumnValueAtRow(CurrencyManager cm, int RowNum)
		{

			// Get the current DataRow from the CurrencyManager.
			// Use the GetParentRow and the DataRelation name to get 
			// the parent row.
			// Return the field value from the parent row.

			try
			{
				DataRow dr			=	((DataView)cm.List)[RowNum].Row;
				DataRow drParent	=	dr.GetParentRow(relationName);
				return drParent[parentField].ToString();
			}
			catch
			{
				return "";   // Necessary when adding rows.
			}
		}

		protected override bool Commit(CurrencyManager cm, int RowNum)
		{
			return false;   // Dummy implementation because it is read-only
		}

		public new bool ReadOnly   // Hide base member ReadOnly.
		{
			get
			{
				return true;
			}
		}
	}

	
	
	/// <summary>
	/// Implementation of a ComboBox as a column in a DataGrid
	/// </summary>
	public class DataGridComboBoxColumn : DataGridColumnStyle 
	{
		private int			_xMargin		=	2;
		private int			_yMargin		=	1;
		private ComboBox	_comboBox		=	null;
		private bool		_inEdit			=	false;
		private object		_dataSource		=	null;
		private string		_displayMember	=	null;
		private string		_valueMember	=	null;
		private DataGrid	_dataGrid		=	null;
		private int			_MaxWidth		=	0;
		
		public new bool ReadOnly   // Hide base member ReadOnly.
		{
			get
			{
				if ( _dataGrid != null )
					return _dataGrid.ReadOnly;
				return true;
			}
		}

		public	object	DataSource
		{
			get	{	return _dataSource;}
			set
			{
				_dataSource	=	value;
				if ( _dataSource != null )
				{
					try
					{
						DataTable tb				=	_dataSource as DataTable;
						if ( tb != null )
						{
							if ( tb.Columns[_displayMember] == null )
								throw new Exception(String.Format("Invalid displayMember {0}, aborting",_displayMember));
							if ( tb.Columns[_valueMember] == null )
								throw new Exception(String.Format("Invalid valueMember {0}, aborting",_valueMember));
							tb.RowChanged	+=	new DataRowChangeEventHandler(this.DataRowChanged);
						}
						else
						{
							DataView dv				=	_dataSource as DataView;
							if ( dv != null )
							{
								if ( dv.Table.Columns[_displayMember] == null )
									throw new Exception(String.Format("Invalid displayMember {0}, aborting",_displayMember));
								if ( dv.Table.Columns[_valueMember] == null )
									throw new Exception(String.Format("Invalid valueMember {0}, aborting",_valueMember));
								dv.ListChanged	+=	new  System.ComponentModel.ListChangedEventHandler(ListChanged);
							}
							else 	throw new Exception(String.Format("Invalid DataSource object {0}, aborting",_dataSource.ToString()));

						}
						InitSizeFromDataSource();
					}
					catch (Exception)
					{
						_dataSource	=	null;
						throw;
					}
				}
			}
		}

		public	string	DisplayMember
		{
			get	{	return _displayMember;}
			set
			{
				_displayMember			=	value;
				if ( _comboBox != null )
					_comboBox.DisplayMember =	value;
				try
				{
					if ( _dataSource != null )
						InitSizeFromDataSource();
				}
				catch ( Exception )
				{
					_displayMember	=	null;
					throw;
				}
			}
		}

		public	string	ValueMember
		{
			get	{	return _valueMember;}
			set
			{
				_valueMember			=	value;
				if ( _comboBox != null )
					_comboBox.ValueMember	=	value;
			}
		}
		
		public	int	MaxWidth
		{
			get	{	return _MaxWidth;}
			set
			{
				_MaxWidth			=	value;
				Width				=	value;
			}
		}
		
		
		void DataRowChanged(object sender, System.Data.DataRowChangeEventArgs e)
		{
			if ( e.Action != System.Data.DataRowAction.Add )
				return;
			Graphics graphicsContext	=	_dataGrid.CreateGraphics();
			SizeF stringSize			=	graphicsContext.MeasureString(e.Row[_displayMember].ToString(), _dataGrid.Font);
			if ( stringSize.Width > _comboBox.DropDownWidth ) 
			{
				_comboBox.DropDownWidth	=	(int)Math.Ceiling(stringSize.Width);
				if ( _MaxWidth == 0 )
					this.Width				=	_comboBox.DropDownWidth+25;
			}
			graphicsContext.Dispose();
		}

		void ListChanged(object sender,System.ComponentModel.ListChangedEventArgs e)
		{
			if ( e.ListChangedType != System.ComponentModel.ListChangedType.Reset
					 &&	e.ListChangedType != System.ComponentModel.ListChangedType.ItemAdded )
				return;
			DataView dv				=	_dataSource as DataView;
			if ( dv == null )
				return;
			Graphics graphicsContext	=	_dataGrid.CreateGraphics();
			float	widest				=	_comboBox.DropDownWidth;
			foreach ( System.Data.DataRowView  dr in dv ) 
			{
				SizeF stringSize		=	graphicsContext.MeasureString(dr[_displayMember].ToString(), _dataGrid.Font);
				if ( stringSize.Width > widest ) 
					widest		=	stringSize.Width;
				}
			if ( widest > _comboBox.DropDownWidth ) 
			{
				_comboBox.DropDownWidth		=	(int)Math.Ceiling(widest);
				if ( _MaxWidth == 0 )
					this.Width					=	_comboBox.DropDownWidth+25; 
			}
			graphicsContext.Dispose();
		}
		
		protected override void SetDataGrid(DataGrid gr)
		{
			SetDataGridInColumn(gr);
		}
		
		protected override void SetDataGridInColumn(DataGrid gr)
		{
			if ( gr == _dataGrid )
				return;
			if ( _dataGrid != null )
			{
				if ( _comboBox != null && _dataGrid.Contains(_comboBox) )
					_dataGrid.Controls.Remove(_comboBox);
				}
			
			_comboBox				=	new ComboBox();
			_comboBox.Visible		=	false;
			if ( _displayMember != null )
				_comboBox.DisplayMember =	_displayMember;
			
			if ( _valueMember != null )
				_comboBox.ValueMember	=	_valueMember;
			
			_comboBox.DropDownStyle =	ComboBoxStyle.DropDownList;
			_dataGrid				=	gr;
			_dataGrid.Controls.Add(_comboBox);
			try
			{
				InitSizeFromDataSource();
			}
			catch(Exception ex)
			{
				_comboBox	=	null;
				_dataGrid	=	null;
				throw ex;
			}
		}

		
		private void InitSizeFromDataSource()
		{
			if ( _dataGrid == null || _dataSource == null )
				return;
			Graphics graphicsContext	=	_dataGrid.CreateGraphics();
			float widest				=	0.0F;
			DataTable tb				=	_dataSource as DataTable;

			if ( _comboBox.DataSource != _dataSource )
				_comboBox.DataSource		=	_dataSource;

			SizeF stringSize		=	graphicsContext.MeasureString(this.HeaderText,_dataGrid.Font);
			if ( stringSize.Width > widest ) 
				widest		=	stringSize.Width;
			if ( tb != null )
			{
				foreach ( DataRow dr in tb.Rows ) 
				{
					stringSize		=	graphicsContext.MeasureString(dr[_displayMember].ToString(), _dataGrid.Font);
					if ( stringSize.Width > widest ) 
						widest		=	stringSize.Width;
				
				}
			}
			else
			{
				DataView dv				=	_dataSource as DataView;
				if ( dv != null )
				{
					foreach ( System.Data.DataRowView  dr in dv ) 
					{
						stringSize		=	graphicsContext.MeasureString(dr[_displayMember].ToString(), _dataGrid.Font);
						if ( stringSize.Width > widest ) 
							widest		=	stringSize.Width;
					}
				}
			}

			_comboBox.DropDownWidth		=	(int)Math.Ceiling(widest);
			if ( _MaxWidth == 0 )
				this.Width				=	_comboBox.DropDownWidth+25; // Add the space for the dropdown arrow
			graphicsContext.Dispose();
		}
		

		void CbDatSourceChanged(object sender, System.EventArgs e)
		{
			if ( _dataSource != null )
				InitSizeFromDataSource();
		}
		/// <summary>
		/// One of the constructors
		/// </summary>
		/// <param name="colName">The name of the column</param>
		/// <param name="dataSource">The datasource that contains the lookup table</param>
		/// <param name="displayMember">The member of the lookuptable to display</param>
		/// <param name="valueMember">The member of the lookuptable with the value</param>
		/// <param name="dataGrid">The datagrid parent of this column</param>
		public DataGridComboBoxColumn(string HeaderTxt, string colName, object dataSource, string displayMember, string valueMember, DataGrid dataGrid) 
		{
			_displayMember			=	displayMember;
			_valueMember			=	valueMember;

			this.MappingName		=	colName;
			this.HeaderText			=	HeaderTxt;

			DataSource				=	dataSource;
			SetDataGridInColumn(dataGrid);
		}

		/// <summary>
		/// Another constructors
		/// </summary>
		/// <param name="colName">The name of the column</param>
		/// <param name="displayMember">The member of the lookuptable to display</param>
		/// <param name="valueMember">The member of the lookuptable with the value</param>
		public DataGridComboBoxColumn(object dataSource, string displayMember, string valueMember) 
		{
			_displayMember			=	displayMember;
			_valueMember			=	valueMember;
			DataSource				=	dataSource;
		}

		/// <summary>
		/// Standard override
		/// </summary>
		/// <param name="rowNum"></param>
		protected override void Abort(int rowNum) 
		{
			_inEdit	=	false;
			if ( _comboBox != null && _comboBox.Visible	)
				_comboBox.Hide();
		}
		/// <summary>
		/// Standard override
		/// </summary>
		/// <param name="dataSource"></param>
		/// <param name="rowNum"></param>
		/// <returns></returns>
		protected override bool Commit(CurrencyManager dataSource,int rowNum) 
		{
			if ( !_inEdit || _comboBox == null ) 
				return true;
			try 
			{
				object _value		= _comboBox.SelectedValue;
				if ( GetText(_value) == GetText(GetColumnValueAtRow(dataSource, rowNum)) )
					return true;
				if( NullText.Equals(_value) ) 
				{
					_value = System.Convert.DBNull; 
				}
				this.SetColumnValueAtRow(dataSource, rowNum, _value);
			}
			catch 
			{
				return false;
			}
			finally 
			{
				_inEdit	=	false;
				_comboBox.Hide();
			}
			return true;
		}
		
		/// <summary>
		/// Standard override
		/// </summary>
		/// <param name="source"></param>
		/// <param name="rowNum"></param>
		/// <param name="bounds"></param>
		/// <param name="readOnly"></param>
		/// <param name="instantText"></param>
		/// <param name="cellIsVisible"></param>
		protected override void Edit(CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible) 
		{
			if ( _comboBox == null )
				return;
			if ( ReadOnly )
				return;
			if(	!cellIsVisible ) 
				return;
			try
			{
				Rectangle originalBounds	=	bounds;
				originalBounds.Offset(_xMargin, _yMargin);
				originalBounds.Width				-=	_xMargin * 2;
				originalBounds.Height				-=	_yMargin;
				_comboBox.Bounds			=	originalBounds;
				_comboBox.Visible			=	true;
				_inEdit						=	true;
			
				if( instantText != null ) 
				{
					_comboBox.SelectedValue =	instantText;
					int End					=	_comboBox.Text.Length;
					_comboBox.Select(End, 0);
				} 
				else 
				{
					_comboBox.SelectedValue		=	GetText(GetColumnValueAtRow(source, rowNum));
					_comboBox.SelectAll();
				}

			}
			catch
			{}
		}
		
		/// <summary>
		/// Standard override
		/// </summary>
		/// <returns></returns>
		protected override int GetMinimumHeight() 
		{
			return _comboBox.PreferredHeight + _yMargin;
		}
		
		/// <summary>
		/// Standard override
		/// </summary>
		/// <param name="g"></param>
		/// <param name="val"></param>
		/// <returns></returns>
		protected override int GetPreferredHeight(Graphics g ,object val) 
		{
			return FontHeight + _yMargin;
		}
		
		/// <summary>
		/// Standard override
		/// </summary>
		/// <param name="g"></param>
		/// <param name="val"></param>
		/// <returns></returns>
		protected override Size GetPreferredSize(Graphics g, object val) 
		{
			Size _extents	=	Size.Ceiling(g.MeasureString(GetText(val), this.DataGridTableStyle.DataGrid.Font));
			_extents.Width	+=	_xMargin * 2 ;
			_extents.Height +=	_yMargin;
			return _extents;
		}
		
		/// <summary>
		/// Standard override
		/// </summary>
		/// <param name="g"></param>
		/// <param name="bounds"></param>
		/// <param name="source"></param>
		/// <param name="rowNum"></param>
		protected override void Paint(Graphics g,Rectangle bounds,CurrencyManager source,int rowNum) 
		{
			Paint(g, bounds, source, rowNum, false);
		}

		/// <summary>
		/// Standard override
		/// </summary>
		/// <param name="g"></param>
		/// <param name="bounds"></param>
		/// <param name="source"></param>
		/// <param name="rowNum"></param>
		/// <param name="alignToRight"></param>
		protected override void Paint(Graphics g,Rectangle bounds,CurrencyManager source,int rowNum, bool alignToRight) 
		{
			if ( _dataSource == null )
				return;
			bool	selectedRow	=	false;
			bool	dgSelectedRow	=	false;
			try
			{
				if ( source.Position == rowNum )
					selectedRow	=	true;
				if ( _dataGrid.IsSelected(rowNum) )
					dgSelectedRow	=	true;
				string text		=	GetText(GetColumnValueAtRow(source, rowNum));
				DataTable dt	=	_dataSource as DataTable;
				if ( dt != null && text != string.Empty )
				{
					foreach ( DataRow dr in dt.Rows ) 
					{
						if ( dr[_valueMember].ToString() == text ) 
						{
							text	=	dr[_displayMember].ToString();
							break;
						}
					}
					PaintText(g, bounds, text, alignToRight,rowNum,selectedRow,dgSelectedRow);
					return;
				}
				DataView dv = _dataSource as DataView;
				if ( dv != null )
				{
					foreach (DataRowView dr in dv) 
					{
						if ( dr[_valueMember].ToString() == text ) 
						{
							text	=	dr[_displayMember].ToString();
							break;
						}
					}
					PaintText(g, bounds, text, alignToRight,rowNum,selectedRow,dgSelectedRow);
				}
			}
			catch
			{}
		}

		// Helper functions
		private void PaintText(Graphics g ,Rectangle bounds, string text,bool alignToRight,int rowNum,bool selectedRow,bool dgSelectedRow) 
		{
			Brush backBrush			=	null;
			Brush foreBrush			=	null;

			if ( selectedRow && dgSelectedRow )
			{
				backBrush			=	new SolidBrush(this.DataGridTableStyle.SelectionBackColor);
				foreBrush			=	new SolidBrush(this.DataGridTableStyle.SelectionForeColor);
			}
			else
			{
				if ( ReadOnly && selectedRow && ( _dataGrid.CurrentCell.ColumnNumber == this.DataGridTableStyle.GridColumnStyles.IndexOf(this)) )
					backBrush		=	new SolidBrush(System.Drawing.Color.LightGray);
				else if ( rowNum % 2 == 0 )
					backBrush	=	new SolidBrush(this.DataGridTableStyle.BackColor);
				else	backBrush	=	new SolidBrush(this.DataGridTableStyle.AlternatingBackColor);
				foreBrush			=	new SolidBrush(this.DataGridTableStyle.ForeColor);
			}
			Rectangle rect			=	bounds;
			RectangleF rectF		=	rect; 
			StringFormat format		=	new StringFormat();
			if( alignToRight ) 
			{
				format.FormatFlags	=	StringFormatFlags.DirectionRightToLeft;
			}
			switch( this.Alignment ) 
			{
				case HorizontalAlignment.Left:
					format.Alignment	=	StringAlignment.Near;
					break;
				case HorizontalAlignment.Right:
					format.Alignment	=	StringAlignment.Far;
					break;
				case HorizontalAlignment.Center:
					format.Alignment	=	StringAlignment.Center;
					break;
			}
			format.FormatFlags	=	StringFormatFlags.NoWrap;
			g.FillRectangle(backBrush, rect);
			rectF.Offset(0, _yMargin);
			rectF.Height		-=	_yMargin;
			g.DrawString(text, this.DataGridTableStyle.DataGrid.Font, foreBrush, rectF, format);
			format.Dispose();
		}

		private string GetText(object val) 
		{
			if( val == System.DBNull.Value ) 
				return this.NullText;
			if( val != null ) 
				return val.ToString();
			return this.NullText;
		}
	}
}